/*
 * Param.cpp
 *
 *  Created on: Dec 17, 2014
 *      Author: Phong
 */

#include "Param.h"

Param::Param (int dim, int wdim, int nwords, int npos, int ndeprel, real r1, real r2) : SafeShare() {
	refCount = 1;

	// common i/o
	anonRep[0] = Matrix::uniform(dim, -r2, r2); weights.push_back(anonRep[0]);
	anonRep[1] = Matrix::uniform(dim, -r2, r2); weights.push_back(anonRep[1]);

	// project wembs onto higher dimension space
	Ww = Matrix::uniform(dim, wdim, -r1, r1); weights.push_back(Ww);
	bw = Matrix::uniform(dim, 0, 0); weights.push_back(bw);

	// for computing composition rept
	Wch = Matrix::uniform(dim, dim, -r1, r1); weights.push_back(Wch);
	bc = Matrix::uniform(dim, 0, 0); weights.push_back(bc);
	for (int dir = 0; dir < 2; dir++) {
		for (int dr = 0; dr < ndeprel; dr++) {
			Matrix* w = Matrix::uniform(dim, dim, -r1, r1);
			Wc[dir].push_back(w);
			weights.push_back(w);
		}
	}

	// for computing generation rept
	for (int dir = 0; dir < 2; dir++) {
		Wgh[dir] = Matrix::uniform(dim, dim, -r1, r1); weights.push_back(Wgh[dir]);
		Wgp[dir] = Matrix::uniform(dim, dim, -r1, r1); weights.push_back(Wgp[dir]);
		bg[dir] = Matrix::uniform(dim, 0, 0); weights.push_back(bg[dir]);
		for (int dr = 0; dr < ndeprel; dr++) {
			Matrix* w = Matrix::uniform(dim, dim, -r1, r1);
			Wg[dir].push_back(w);
			weights.push_back(w);
		}
	} // 80

	// for partial gen. rep.
	for (int dir = 0; dir < 2; dir++) {
		Wgh_p[dir] = Matrix::uniform(dim, dim, -r1, r1); weights.push_back(Wgh_p[dir]);
		Wgp_p[dir] = Matrix::uniform(dim, dim, -r1, r1); weights.push_back(Wgp_p[dir]);
		Wgs_p[dir] = Matrix::uniform(dim, dim, -r1, r1); weights.push_back(Wgs_p[dir]);
		bg_p[dir] = Matrix::uniform(dim, 0, 0); weights.push_back(bg_p[dir]);
		Wtr[dir] = Matrix::uniform(dim, dim, -r1, r1); weights.push_back(Wtr[dir]);
		btr[dir] = Matrix::uniform(dim, 0, 0); weights.push_back(btr[dir]);
		for (int dr = 0; dr < ndeprel; dr++) {
			Matrix* w = Matrix::uniform(dim, dim, -r1, r1);
			Wg_p[dir].push_back(w);
			weights.push_back(w);
		}
	}


	// for computing softmaxs
	Wdr = Matrix::uniform(ndeprel+1, dim, -r2, r2); weights.push_back(Wdr);
	bdr = Matrix::uniform(ndeprel+1, 0, 0); weights.push_back(bdr);

	Wpos = Matrix::uniform(npos, dim, -r2, r2); weights.push_back(Wpos);
	Wdrpos = Matrix::uniform(npos, ndeprel, -r2, r2); weights.push_back(Wdrpos);
	bpos = Matrix::uniform(npos, 0, 0); weights.push_back(bpos);

	for (int i = 0; i < nwords; i++)
		Wword.push_back(Matrix::uniform(dim, -r2, r2)); // push_back it later
	Wdrword = Matrix::uniform(nwords, ndeprel, -r2, r2); weights.push_back(Wdrword);
	Wposword = Matrix::uniform(nwords, npos, -r2, r2); weights.push_back(Wposword);
	bword = Matrix::uniform(nwords, 0, 0); weights.push_back(bword);

	// for embeddings
	for (int i = 0; i < npos; i++) {
		Matrix* w = Matrix::uniform(dim, -r2, r2);
		Lpos.push_back(w);
		weights.push_back(w);
	}

	nMatricesWoWE = (int)weights.size();

	for (int i = 0; i < nwords; i++) weights.push_back(Wword[i]);

	for (int i = 0; i < nwords; i++) {
		Matrix* w = Matrix::uniform(wdim, -r2, r2);
		L.push_back(w);
		weights.push_back(w);
	}
}

void Param::save(ofstream &f) {
	f << nMatricesWoWE << endl;

	Ww->save(f); bw->save(f);

	anonRep[0]->save(f); anonRep[1]->save(f);

	Wch->save(f); bc->save(f);
	f << Wc[0].size() << endl;
	for (unsigned int i = 0; i < Wc[0].size(); i++) {
		Wc[0][i]->save(f);
		Wc[1][i]->save(f);
	}

	for (int dir = 0; dir < 2; dir++) {
		Wgh[dir]->save(f);
		Wgp[dir]->save(f);
		bg[dir]->save(f);
		f << Wg[dir].size() << endl;
		for (unsigned int i = 0; i < Wg[dir].size(); i++)
			Wg[dir][i]->save(f);
	}

	for (int dir = 0; dir < 2; dir++) {
		Wgh_p[dir]->save(f);
		Wgp_p[dir]->save(f);
		Wgs_p[dir]->save(f);
		bg_p[dir]->save(f);
		Wtr[dir]->save(f);
		btr[dir]->save(f);
		f << Wg_p[dir].size() << endl;
		for (unsigned int i = 0; i < Wg[dir].size(); i++)
			Wg_p[dir][i]->save(f);
	}

	Wdr->save(f); bdr->save(f);
	Wpos->save(f); Wdrpos->save(f); bpos->save(f);

	f << Wword.size() << endl;
	for (unsigned int i = 0; i < Wword.size(); i++)
		Wword[i]->save(f);
	Wdrword->save(f); Wposword->save(f); bword->save(f);

	f << Lpos.size() << endl;
	for (unsigned int i = 0; i < Lpos.size(); i++)
		Lpos[i]->save(f);
	f << L.size() << endl;
	for (unsigned int i = 0; i < L.size(); i++)
		L[i]->save(f);

	f << endl;
}

Param* Param::load(ifstream &f) {
	Param* param = new Param();
	int n;

	f >> param->nMatricesWoWE;

	param->Ww = Matrix::load(f); param->bw = Matrix::load(f);

	param->anonRep[0] = Matrix::load(f); param->anonRep[1] = Matrix::load(f);

	param->Wch = Matrix::load(f); param->bc = Matrix::load(f);
	f >> n;
	for (int i = 0; i < n; i++) {
		param->Wc[0].push_back(Matrix::load(f));
		param->Wc[1].push_back(Matrix::load(f));
	}

	for (int dir = 0; dir < 2; dir++) {
		param->Wgh[dir] = Matrix::load(f);
		param->Wgp[dir] = Matrix::load(f);
		param->bg[dir] = Matrix::load(f);
		f >> n;
		for (int i = 0; i < n; i++)
			param->Wg[dir].push_back(Matrix::load(f));
	}

	for (int dir = 0; dir < 2; dir++) {
		param->Wgh_p[dir] = Matrix::load(f);
		param->Wgp_p[dir] = Matrix::load(f);
		param->Wgs_p[dir] = Matrix::load(f);
		param->bg_p[dir] = Matrix::load(f);
		param->Wtr[dir] = Matrix::load(f);
		param->btr[dir] = Matrix::load(f);
		f >> n;
		for (int i = 0; i < n; i++)
			param->Wg_p[dir].push_back(Matrix::load(f));
	}

	param->Wdr = Matrix::load(f); param->bdr = Matrix::load(f);
	param->Wpos = Matrix::load(f); param->Wdrpos = Matrix::load(f); param->bpos = Matrix::load(f);

	f >> n;
	for (int i = 0; i < n; i++)
		param->Wword.push_back(Matrix::load(f));
	param->Wdrword = Matrix::load(f); param->Wposword = Matrix::load(f); param->bword = Matrix::load(f);

	f >> n;
	for (int i = 0; i < n; i++)
		param->Lpos.push_back(Matrix::load(f));
	f >> n;
	for (int i = 0; i < n; i++)
		param->L.push_back(Matrix::load(f));

	return param;
}

void Param::fill(real value) {
	for (unsigned int i = 0; i < weights.size(); i++) {
		weights[i]->fill(value);
	}
}

Param::~Param() {
	for (unsigned int i = 0; i < weights.size(); i++) {
		delete weights[i];
	}
}
